package com.kantboot.system.user.service.impl;

import com.kantboot.api.varcode.domain.dto.ApiVarCodeDTO;
import com.kantboot.api.varcode.service.IApiVarCodeService;
import com.kantboot.functional.common.service.ICommonKantbootRsaService;
import com.kantboot.system.user.dao.repository.entity.SysUserRepository;
import com.kantboot.system.user.dao.repository.vo.SysUserVOOfSelfRepository;
import com.kantboot.system.user.domain.entity.SysUser;
import com.kantboot.system.user.domain.vo.LoginVO;
import com.kantboot.system.user.domain.vo.SysUserOfSelfVO;
import com.kantboot.system.user.exception.SystemUserException;
import com.kantboot.system.user.service.ISysLoginService;
import com.kantboot.system.user.service.ISysTokenService;
import com.kantboot.system.user.service.ISysUserService;
import com.kantboot.util.common.http.HttpRequestHeaderUtil;
import com.kantboot.util.common.password.KantbootPassword;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

@Service
public class SysLoginServiceImpl implements ISysLoginService {

    @Resource
    private SysUserRepository sysUserRepository;

    @Resource
    private KantbootPassword kantbootPassword;

    @Resource
    private ISysTokenService tokenService;

    @Resource
    private SysUserVOOfSelfRepository sysUserVOOfSelfShowRepository;

    @Resource
    private ICommonKantbootRsaService kantbootRsaService;

    @Resource
    private HttpRequestHeaderUtil httpRequestHeaderUtil;

    @Resource
    private IApiVarCodeService apiVarCodeService;

    @Resource
    private ISysUserService userService;


    /**
     * 根据用户id查询用户信息
     * @param userId 用户id
     * @return 用户信息
     */
    private SysUserOfSelfVO getById(Long userId){
        return sysUserVOOfSelfShowRepository.findById(userId)
                .orElseThrow(() ->
                        // 一般不会出现这种情况，因为前面已经判断过用户名是否存在，如果不存在，就会抛出异常
                        // 提示用户不存在
                        SystemUserException.USER_NOT_EXIST
                );
    }


    /**
     * 注册
     * @param username 用户名
     * @param password 密码
     * @return 登录信息
     */
    @Override
    public LoginVO register(String username, String password) {
        // 判断用户名是否存在
        if(sysUserRepository.existsByUsername(username)){
            // 用户名已存在，抛出异常，提示前端用户名已存在
            throw SystemUserException.USERNAME_EXIST;
        }

        // 密码加密
        String passwordEncoded = kantbootPassword.encode(password);
        SysUser sysUser = new SysUser()
                .setUsername(username)
                .setPassword(passwordEncoded);
        // 保存用户
        SysUser save = userService.createNewUser(sysUser.setIsInit(false).setIsTemporary(false));

        // 根据用户id生成token
        String token = tokenService.generateToken(save.getId());
        // 根据用户id查询用户信息
        return new LoginVO().setToken(token).setUserInfo(getById(save.getId()));
    }

    @Override
    public LoginVO login(String username, String password) {
        // 判断用户名是否存在
        if(!sysUserRepository.existsByUsername(username)){
            // 用户名不存在，抛出异常，提示前端用户不存在
            throw SystemUserException.USERNAME_NOt_EXIST;
        }

        // 根据用户名查询密码
        String passwordFromDB = sysUserRepository.findPasswordByUsername(username);

        // 判断密码是否正确
        if(!kantbootPassword.matches(password,passwordFromDB)){
            // 密码错误，抛出异常，提示前端密码错误
            throw SystemUserException.PASSWORD_ERROR;
        }

        // 根据用户名查询用户id
        Long userId = sysUserRepository.findIdByUsername(username);
        // 生成token
        String token = tokenService.generateToken(userId);
        return new LoginVO().setToken(token).setUserInfo(getById(userId));
    }


    /**
     * 安全注册
     * @param username 用户名
     * @param password 密码
     * @return 登录信息
     */
    @Override
    public LoginVO registerWithSecurity(String username, String password) {
        // 解密用户名
        String usernameDecrypted = kantbootRsaService.decryptAndDelete(username);
        // 解密密码
        String passwordDecrypted = kantbootRsaService.decryptAndDelete(password);
        return register(usernameDecrypted,passwordDecrypted);
    }

    /**
     * 安全登录
     * @param username 用户名
     * @param password 密码
     * @return 登录信息
     */
    @Override
    public LoginVO loginWithSecurity(String username, String password) {
        // 解密用户名
        String usernameDecrypted = kantbootRsaService.decryptAndDelete(username);
        // 解密密码
        String passwordDecrypted = kantbootRsaService.decryptAndDelete(password);
        return login(usernameDecrypted,passwordDecrypted);
    }

    /**
     * 登出
     */
    @Override
    public void logout() {
        String token = httpRequestHeaderUtil.getToken();
        tokenService.deleteToken(token);
    }

    /**
     * 手机号+密码登录
     */
    @Override
    public LoginVO loginWithPhoneAndPassword(String phone, String password) {
        // 判断手机号是否存在
        if(!sysUserRepository.existsByPhone(phone)){
            // 手机号不存在，抛出异常，提示前端手机号不存在
            throw SystemUserException.PHONE_NOT_EXIST;
        }

        // 根据手机号查询密码
        String passwordFromDB = sysUserRepository.findPasswordByPhone(phone);

        // 判断密码是否正确
        if(!kantbootPassword.matches(password,passwordFromDB)){
            // 密码错误，抛出异常，提示前端密码错误
            throw SystemUserException.PASSWORD_ERROR;
        }

        // 根据手机号查询用户id
        Long userId = sysUserRepository.findIdByPhone(phone);
        // 生成token
        String token = tokenService.generateToken(userId);
        return new LoginVO().setToken(token).setUserInfo(getById(userId));
    }

    /**
     * 手机号+密码登录（安全）
     */
    @Override
    public LoginVO loginWithPhoneAndPasswordWithSecurity(String phone, String password) {
        // 解密手机号
        String phoneDecrypted = kantbootRsaService.decryptAndDelete(phone);
        // 解密密码
        String passwordDecrypted = kantbootRsaService.decryptAndDelete(password);
        return loginWithPhoneAndPassword(phoneDecrypted,passwordDecrypted);
    }

    /**
     * 邮箱+密码登录
     */
    @Override
    public LoginVO loginWithEmailAndPassword(String email, String password) {
        // 判断邮箱是否存在
        if(!sysUserRepository.existsByEmail(email)){
            // 邮箱不存在，抛出异常，提示前端邮箱不存在
            throw SystemUserException.EMAIL_NOT_EXIST;
        }

        // 根据邮箱查询密码
        String passwordFromDB = sysUserRepository.findPasswordByEmail(email);

        // 判断密码是否正确
        if(!kantbootPassword.matches(password,passwordFromDB)){
            // 密码错误，抛出异常，提示前端密码错误
            throw SystemUserException.PASSWORD_ERROR;
        }

        // 根据邮箱查询用户id
        Long userId = sysUserRepository.findIdByEmail(email);
        // 生成token
        String token = tokenService.generateToken(userId);
        return new LoginVO().setToken(token).setUserInfo(getById(userId));
    }

    /**
     * 邮箱+密码登录（安全）
     */
    @Override
    public LoginVO loginWithEmailAndPasswordWithSecurity(String email, String password) {
        // 解密邮箱
        String emailDecrypted = kantbootRsaService.decryptAndDelete(email);
        // 解密密码
        String passwordDecrypted = kantbootRsaService.decryptAndDelete(password);
        return loginWithEmailAndPassword(emailDecrypted,passwordDecrypted);
    }

    @Override
    public LoginVO loginWithPhoneAndVarCode(String phone, String varCode) {
        ApiVarCodeDTO dto = new ApiVarCodeDTO();
        dto.setTo(phone);
        dto.setTypeCode("sms");
        dto.setSceneCode("login");
        dto.setValue(varCode);
        // 验证验证码是否正确
        if(!apiVarCodeService.check(dto)){
            // 验证码错误，抛出异常，提示前端验证码错误
            throw SystemUserException.VAR_CODE_ERROR;
        }
        if(!sysUserRepository.existsByPhone(phone)){
            userService.createNewUser(new SysUser().setPhone(phone));
        }
        Long idByPhone = sysUserRepository.findIdByPhone(phone);
        LoginVO loginVO = new LoginVO();
        loginVO.setToken(tokenService.generateToken(idByPhone));
        loginVO.setUserInfo(getById(idByPhone));
        return loginVO;
    }

    @Override
    public LoginVO loginWithPhoneAndVarCodeWithSecurity(String phone, String varCode) {
        String phoneDecrypted = kantbootRsaService.decryptAndDelete(phone);
        String varCodeDecrypted = kantbootRsaService.decryptAndDelete(varCode);
        return loginWithPhoneAndVarCode(phoneDecrypted,varCodeDecrypted);
    }

    @Override
    public LoginVO loginWithEmailAndVarCode(String email, String varCode) {
        ApiVarCodeDTO dto = new ApiVarCodeDTO();
        dto.setTo(email);
        dto.setTypeCode("email");
        dto.setSceneCode("login");
        dto.setValue(varCode);
        // 验证验证码是否正确
        if(!apiVarCodeService.check(dto)){
            // 验证码错误，抛出异常，提示前端验证码错误
            throw SystemUserException.VAR_CODE_ERROR;
        }
        if(!sysUserRepository.existsByEmail(email)){
            userService.createNewUser(new SysUser().setEmail(email));
        }
        Long idByEmail = sysUserRepository.findIdByEmail(email);
        LoginVO loginVO = new LoginVO();
        loginVO.setToken(tokenService.generateToken(idByEmail));
        loginVO.setUserInfo(getById(idByEmail));
        return loginVO;
    }

    @Override
    public LoginVO loginWithEmailAndVarCodeWithSecurity(String email, String varCode) {
        String emailDecrypted = kantbootRsaService.decryptAndDelete(email);
        String varCodeDecrypted = kantbootRsaService.decryptAndDelete(varCode);
        return loginWithEmailAndVarCode(emailDecrypted,varCodeDecrypted);
    }


    @Override
    public LoginVO registerWithPhoneAndVarCode(String phone, String varCode, String password) {
        ApiVarCodeDTO dto = new ApiVarCodeDTO();
        dto.setTo(phone);
        dto.setTypeCode("sms");
        dto.setSceneCode("register");
        dto.setValue(varCode);
        // 验证验证码是否正确
        if(!apiVarCodeService.check(dto)){
            // 验证码错误，抛出异常，提示前端验证码错误
            throw SystemUserException.VAR_CODE_ERROR;
        }
        if(sysUserRepository.existsByPhone(phone)){
            // 用户名已存在，抛出异常，提示前端用户名已存在
            throw SystemUserException.PHONE_EXIST;
        }
        // 密码加密
        String passwordEncoded = kantbootPassword.encode(password);
        SysUser sysUser = new SysUser()
                .setPhone(phone)
                .setPassword(passwordEncoded);
        // 保存用户
        SysUser save = userService.createNewUser(sysUser.setIsInit(false).setIsTemporary(false));
        // 根据用户id生成token
        String token = tokenService.generateToken(save.getId());
        // 根据用户id查询用户信息
        return new LoginVO().setToken(token).setUserInfo(getById(save.getId()));
    }

    @Override
    public LoginVO registerWithPhoneAndVarCodeWithSecurity(String phone, String varCode, String password) {
        String phoneDecrypted = kantbootRsaService.decryptAndDelete(phone);
        String varCodeDecrypted = kantbootRsaService.decryptAndDelete(varCode);
        String passwordDecrypted = kantbootRsaService.decryptAndDelete(password);
        return registerWithPhoneAndVarCode(phoneDecrypted,varCodeDecrypted,passwordDecrypted);
    }

    @Override
    public LoginVO registerWithEmailAndVarCode(String email, String varCode, String password) {
        ApiVarCodeDTO dto = new ApiVarCodeDTO();
        dto.setTo(email);
        dto.setTypeCode("email");
        dto.setSceneCode("register");
        dto.setValue(varCode);
        // 验证验证码是否正确
        if(!apiVarCodeService.check(dto)){
            // 验证码错误，抛出异常，提示前端验证码错误
            throw SystemUserException.VAR_CODE_ERROR;
        }
        if(sysUserRepository.existsByEmail(email)){
            // 用户名已存在，抛出异常，提示前端邮箱已存在
            throw SystemUserException.EMAIL_EXIST;
        }
        // 密码加密
        String passwordEncoded = kantbootPassword.encode(password);
        SysUser sysUser = new SysUser()
                .setEmail(email)
                .setPassword(passwordEncoded);
        // 保存用户
        SysUser save = userService.createNewUser(sysUser.setIsInit(false).setIsTemporary(false));
        // 根据用户id生成token
        String token = tokenService.generateToken(save.getId());
        // 根据用户id查询用户信息
        return new LoginVO().setToken(token).setUserInfo(getById(save.getId()));
    }

    @Override
    public LoginVO registerWithEmailAndVarCodeWithSecurity(String email, String varCode, String password) {
        String emailDecrypted = kantbootRsaService.decryptAndDelete(email);
        String varCodeDecrypted = kantbootRsaService.decryptAndDelete(varCode);
        String passwordDecrypted = kantbootRsaService.decryptAndDelete(password);
        return registerWithEmailAndVarCode(emailDecrypted,varCodeDecrypted,passwordDecrypted);
    }

}
